/*
 * Copyright 2008 Lucas Tan.
 * This copyright notice must always remain intact whenever you use or distribute 
 * the source code contained in this file.
 * Any usage of any code in this file, either in derived work or
 * through the use of external linkage,
 * must always be credited with the author's name.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * 
 * */
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Xml;
using PassKeeper.Cryptography;

namespace PassKeeper.Data
{
	public sealed class Hasher : Element, IDisposable
	{
		private const string HasherElementName = "Hasher";
		private const string NameAttributeName = "Name";

		private HashAlgorithm _hashAlgo;
		private HasherType _hasherType;


		internal Hasher(Database owner, HasherType hasherType)
			: base(owner)
		{
			_hasherType = hasherType;
			_hashAlgo = Create(hasherType);
		}

		private static HashAlgorithm Create(HasherType hasherType)
		{
			switch (hasherType)
			{
			case HasherType.SHA512:
				return new SHA512ManagedHasher();
			}

			throw new ArgumentException("Unknown hasher type.", "hasherType");
		}

		public void Dispose()
		{
			
				((IDisposable)_hashAlgo).Dispose();
			
		}

		public override void Deserialize(XmlElement elem)
		{
			if (elem == null)
			{
				throw new ArgumentNullException("elem");
			}

			HasherType hasherType;
			HashAlgorithm hashAlgo = null;

			string name = elem.GetAttribute(NameAttributeName);

			if (string.IsNullOrEmpty(name))
			{
				throw new MissingAttributeException(elem.Name, NameAttributeName);
			}


			try
			{
				hasherType = (HasherType) Enum.Parse(typeof(HasherType), name, false);
			}
			catch (Exception e)
			{
				throw new AttributeParseException(elem.Name, NameAttributeName, e);
			}

			hashAlgo = Create(hasherType);

			((IDisposable) _hashAlgo).Dispose();
			_hashAlgo = hashAlgo;
			_hasherType = hasherType;
		}

		public override void Serialize(XmlElement elem)
		{
			if (elem == null)
			{
				throw new ArgumentNullException("elem");
			}

			elem.SetAttribute(NameAttributeName, Enum.GetName(typeof(HasherType),_hasherType));
		}

		public KeyedHashAlgorithm CreateKeyedHasher()
		{
			switch (_hasherType)
			{
			case HasherType.SHA512:

				return new HMACSHA512();
			}

			throw new Exception("Unrecognized hasher type.");
		}

		protected internal override Element Clone(Database ownerDatabase)
		{
			Hasher hasher = new Hasher(this.OwnerDatabase, _hasherType);
			return hasher;
		}

		public override string TagName
		{
			get
			{
				return HasherElementName;
			}
		}
	}
}
